-
Notifications
You must be signed in to change notification settings - Fork 33
[Thread-Safety] Add Mutex per Interpreter #698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Thread-Safety] Add Mutex per Interpreter #698
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #698 +/- ##
==========================================
+ Coverage 79.83% 81.46% +1.62%
==========================================
Files 9 9
Lines 3962 4213 +251
==========================================
+ Hits 3163 3432 +269
+ Misses 799 781 -18
... and 2 files with indirect coverage changes
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
There were too many comments to post at once. Showing the first 10 out of 13. Check the log or trigger a new build to see more.
lib/CppInterOp/CppInterOp.cpp
Outdated
@@ -224,11 +301,18 @@ std::string Demangle(const std::string& mangled_name) { | |||
return demangle; | |||
} | |||
|
|||
void EnableDebugOutput(bool value /* =true*/) { llvm::DebugFlag = value; } | |||
void EnableDebugOutput(bool value /* =true*/) { | |||
LOCK(getInterpInfo()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a different mental model for this. I was thinking that we can have a StateMutatingSection
RAII object which in turn has a mutex-based locking (if multithreading was enabled) and a 'PushTransactionRAII` (for pch/modules). The object should take a parameter if the change is in clang AST which might trigger a derserialiazation or llvm-only. In the latter case we can skip pushing a transaction.
There will be cases where we need one of the two concepts and not both. We need to design a flexible solution addressing these needs without having to introduce both concepts at the same time when they are not needed.
b689053
to
7659fcb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
7659fcb
to
46697ce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
There were too many comments to post at once. Showing the first 10 out of 19. Check the log or trigger a new build to see more.
46697ce
to
68d616d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
A note for this PR. The Emscripten build of CppInterOp doesn't currently support threads
It is possible to turns threads on, and modify CppInterOp, so that it builds with threads. I did this locally yesterday (I did this in the past before we had tests). The tests can run, but several of our currently passing tests fail with threads enabled. We also get a warning about shared memory for the passing tests. I can put a PR showing my current progress, but I don't know how far I would get enabling past what I already have since shared library with pthreads is labelled as experimental on Emscripten, so we might be trying to fight possible bugs in Emscripten. |
68d616d
to
47d1f58
Compare
47d1f58
to
e6a33f8
Compare
@Vipul-Cariappa can you add tests so that all lines of your patch are covered by tests? |
57caa27
to
97bd9b8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
@vgvassilev Just over 10% over this PR is not covered by tests according to this message. Maybe @Vipul-Cariappa could add more tests to increase this coverage too before this goes in? |
3cf9aec
to
2ed0dfe
Compare
Good point. I’d guess most of the uncovered lines are due to preexisting lack of coverage but would be nice to improve the coverage where possible. |
4feb220
to
1e473ce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
1e473ce
to
ab26665
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
Hi @mcbarton, I am using threads with that new test case I have written. And that test case is failing on WASM. I can just skip it. But was thinking if this can potentially enable it? Any comments or thoughts? @vgvassilev, @mcbarton, The test I have written covers some more lines, but the effort to cover all of the missing lines isn't worth it. I advise we go forward with this. We can gradually cover more lines. |
Disabling the wasm test should be fine. I looked at the missing coverage. Yes, some are not caused by this PR but most are really trivial to add tests for and some are just dead code. |
@Vipul-Cariappa Disabling it is the way to go. We do not currently support threads for the wasm build, and enabling them will quite an involved project from my investigations so far. My progress so far managed to get the tests to run with threads, but we end up with tests failing which currently pass. Also using threads with an Emscripten shared library is currently labelled as experimental. |
84e70b0
to
0afd579
Compare
Skipped the test in WASM. |
I don't know how many commits this is behind main, but it needs rebasing according to the Github interface so we can ci can test your changes with the latest changes on main. |
0afd579
to
61e0584
Compare
You don’t want to spend 30 mins writing these tests to make our coverage happy? |
61e0584
to
c36be86
Compare
The tests which use printf (or anything which tries to write to standard output) will cause the ci to fail on Windows. This is a known issue and these tests will need to be skipped on Windows. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
EXPECT_EQ(members.size(), 0); | ||
|
||
EXPECT_FALSE( | ||
Cpp::InsertOrReplaceJitSymbol("printf", (uint64_t)&printf_jit, I)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
Cpp::InsertOrReplaceJitSymbol("printf", (uint64_t)&printf_jit, I));
^
EXPECT_EQ(members.size(), 0); | ||
|
||
EXPECT_FALSE( | ||
Cpp::InsertOrReplaceJitSymbol("printf", (uint64_t)&printf_jit, I)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: no header providing "uint64_t" is directly included [misc-include-cleaner]
Cpp::InsertOrReplaceJitSymbol("printf", (uint64_t)&printf_jit, I));
^
EXPECT_EQ(f_callable.getKind(), Cpp::JitCall::Kind::kGenericCall); | ||
|
||
EXPECT_FALSE( | ||
Cpp::TakeInterpreter((TInterp_t)1)); // try to take ownership of an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
Cpp::TakeInterpreter((TInterp_t)1)); // try to take ownership of an
^
EXPECT_NE(std::find(includes.begin(), includes.end(), "/non/existent/"), | ||
std::end(includes)); | ||
|
||
EXPECT_TRUE(Cpp::InsertOrReplaceJitSymbol("non_existent", (uint64_t)&f, I)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
EXPECT_TRUE(Cpp::InsertOrReplaceJitSymbol("non_existent", (uint64_t)&f, I));
^
c36be86
to
bc7fac3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
EXPECT_TRUE(Cpp::GetInterpreter()) << "External Interpreter not set"; | ||
Cpp::UseExternalInterpreter(ExtInterp); | ||
EXPECT_EQ(ExtInterp, Cpp::GetInterpreter()); | ||
EXPECT_EQ(ExtInterp, Cpp::TakeInterpreter(ExtInterp)); | ||
|
||
#ifndef CPPINTEROP_USE_CLING | ||
I.release(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: Method called on moved-from object 'I' [clang-analyzer-cplusplus.Move]
I.release();
^
Additional context
unittests/CppInterOp/InterpreterTest.cpp:322: Assuming the condition is false
if (llvm::sys::RunningOnValgrind())
^
unittests/CppInterOp/InterpreterTest.cpp:322: Taking false branch
if (llvm::sys::RunningOnValgrind())
^
unittests/CppInterOp/InterpreterTest.cpp:338: Object 'I' is moved
auto CPPI = Cpp::Interpreter(std::move(I));
^
unittests/CppInterOp/InterpreterTest.cpp:354: Control jumps to 'case 0:' at line 355
EXPECT_NE(ExtInterp, nullptr);
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1886: expanded from macro 'EXPECT_NE'
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:77: expanded from macro 'GTEST_ASSERT_'
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/internal/gtest-port.h:727: expanded from macro 'GTEST_AMBIGUOUS_ELSE_BLOCKER_'
switch (0) \
^
unittests/CppInterOp/InterpreterTest.cpp:354: Assuming the condition is true
EXPECT_NE(ExtInterp, nullptr);
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1886: expanded from macro 'EXPECT_NE'
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^
unittests/CppInterOp/InterpreterTest.cpp:354: Taking true branch
EXPECT_NE(ExtInterp, nullptr);
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1886: expanded from macro 'EXPECT_NE'
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^
unittests/CppInterOp/InterpreterTest.cpp:357: Control jumps to 'case 0:' at line 358
EXPECT_EQ(ExtInterp, Cpp::GetInterpreter());
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1884: expanded from macro 'EXPECT_EQ'
EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:77: expanded from macro 'GTEST_ASSERT_'
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/internal/gtest-port.h:727: expanded from macro 'GTEST_AMBIGUOUS_ELSE_BLOCKER_'
switch (0) \
^
unittests/CppInterOp/InterpreterTest.cpp:357: Assuming the condition is true
EXPECT_EQ(ExtInterp, Cpp::GetInterpreter());
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1884: expanded from macro 'EXPECT_EQ'
EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^
unittests/CppInterOp/InterpreterTest.cpp:357: Taking true branch
EXPECT_EQ(ExtInterp, Cpp::GetInterpreter());
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1884: expanded from macro 'EXPECT_EQ'
EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^
unittests/CppInterOp/InterpreterTest.cpp:358: Control jumps to 'case 0:' at line 359
EXPECT_EQ(ExtInterp, Cpp::TakeInterpreter(ExtInterp));
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1884: expanded from macro 'EXPECT_EQ'
EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:77: expanded from macro 'GTEST_ASSERT_'
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/internal/gtest-port.h:727: expanded from macro 'GTEST_AMBIGUOUS_ELSE_BLOCKER_'
switch (0) \
^
unittests/CppInterOp/InterpreterTest.cpp:358: Assuming the condition is true
EXPECT_EQ(ExtInterp, Cpp::TakeInterpreter(ExtInterp));
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1884: expanded from macro 'EXPECT_EQ'
EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^
unittests/CppInterOp/InterpreterTest.cpp:358: Taking true branch
EXPECT_EQ(ExtInterp, Cpp::TakeInterpreter(ExtInterp));
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest.h:1884: expanded from macro 'EXPECT_EQ'
EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:143: expanded from macro 'EXPECT_PRED_FORMAT2'
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:133: expanded from macro 'GTEST_PRED_FORMAT2_'
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure)
^
build/unittests/googletest-prefix/src/googletest/googletest/include/gtest/gtest_pred_impl.h:78: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^
unittests/CppInterOp/InterpreterTest.cpp:361: Method called on moved-from object 'I'
I.release();
^
@@ -0,0 +1,11 @@ | |||
#ifndef UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H | |||
#define UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: header guard does not follow preferred style [llvm-header-guard]
#define UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H | |
#ifndef GITHUB_WORKSPACE_UNITTESTS_CPPINTEROP_TESTSHAREDLIB2_TESTSHAREDLIB_H | |
#define GITHUB_WORKSPACE_UNITTESTS_CPPINTEROP_TESTSHAREDLIB2_TESTSHAREDLIB_H |
unittests/CppInterOp/TestSharedLib2/TestSharedLib.h:10:
- #endif // UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H
+ #endif // GITHUB_WORKSPACE_UNITTESTS_CPPINTEROP_TESTSHAREDLIB2_TESTSHAREDLIB_H
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done!
LGTM, modulo the comments. Consider squashing all into one commit or condensing a good atomic minimal set of commits...
lib/CppInterOp/CppInterOp.cpp
Outdated
} | ||
|
||
std::string ObjToString(const char* type, void* obj) { | ||
return getInterp().toString(type, obj); | ||
LOCK(getInterpInfo(NULLPTR)); // FIXME: not enough information to lock the | ||
// corrent interpreter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// corrent interpreter | |
// current interpreter |
Please move the comment above the line.
bc7fac3
to
ab93975
Compare
Have a mutex for each interpreter instance create. Only use the lock at writes to the AST. Use hashmap to identify Sema & AST from individual Decl We need to identify which interpreter a Decl belongs to, when using multiple interpreter. We do it by checking which `clang::ASTContext` the `clang::Decl` belongs We maintain a map: `clang::ASTContext -> Cpp::InterpreterInfo`. Using this map, we identify the correct interpreter. Note that the mutex is stored in the InterpreterInfo class. There are 2 usecases for this: 1. We can now lock the correct interpreter making it thread safe. 2. User of `libCppInterOp` need not set the correct active interpreter using `Cpp::ActivateInterpreter`, this information can be retrived using the map.
Pops interpreter without destroying it. Destruction to be handled by the caller. This is to be used along with UserExternalInterpreter, where libCppInterOp is not owning the interpreter instance.
Functions like Declare compile code into the top-most interpreter in the stack. If the user wants to compile the code to some other interpreter instance, user can use the `TInterp_t` argument to specify the interpreter. This is also required to lock the correct interpreter instance. If `TInterp_t` is null, we assume the correct interpreter to lock is the top of the stack. This assumption might be wrong at some cases.
Add test to run things in parallel Add documentation for developers
ab93975
to
d55415e
Compare
c42c907
into
compiler-research:main
Big changes in this PR. Some parts of the explanation might be like a conversation.
Mutex lock per interpreter.
Question: Do we need a per-interpreter lock?
Answer: Yes. Ideally, that would improve the performance in multi-threaded cases.
Question: Does the InterOp API fully support dispatching queries (some kind of lookup) or compiling code across multiple interpreters at the same time?
Answer: Actually, (I guess) No. Our API only supports stack-like access of multiple interpreters.
Example code that will not work:
But you can make the above example work, if the user rotates the
sInterpreters
.Example:
Question: Ok. So is there a way for InterOp is maintain the rotation thing?
Answer: Would not be a easy thing to achieve. From my initial view on the matter, it might be possible. But a more important question; Should we support such usecases?
Question: Ok. So given the limitation of using multiple interpreter but only as a stack-access. Do we need a mutex lock per interpreter?
Answer: No, the user can only access the top most interpreter at a time. We don't need a mutex per interpreter. (Let me know if my reasoning is wrong somewhere)
Testing this by running in parallel
gtest does not support running in parallel (I could not find anything with my google search). But there is this project, gtest-parallel, that can split the tasks into separate isolated processes. But that is not what we want. We want to split the tests to run in parallel threads that share the same interpreter instance.
Code recovery RAII
@vgvassilev, I need some pointers on incorporating the codegen error recovery RAII. I don't think we should combine the two into the same class, but let me know your opinion. And how should I go about doing it?